index.js ➔ outputHelpIfNecessary   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 6
nc 6
nop 2
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
/**
2
 * Module dependencies.
3
 */
4
5
var EventEmitter = require('events').EventEmitter;
6
var spawn = require('child_process').spawn;
7
var path = require('path');
8
var dirname = path.dirname;
9
var basename = path.basename;
10
var fs = require('fs');
11
12
/**
13
 * Expose the root command.
14
 */
15
16
exports = module.exports = new Command();
17
18
/**
19
 * Expose `Command`.
20
 */
21
22
exports.Command = Command;
23
24
/**
25
 * Expose `Option`.
26
 */
27
28
exports.Option = Option;
29
30
/**
31
 * Initialize a new `Option` with the given `flags` and `description`.
32
 *
33
 * @param {String} flags
34
 * @param {String} description
35
 * @api public
36
 */
37
38
function Option(flags, description) {
39
  this.flags = flags;
40
  this.required = ~flags.indexOf('<');
41
  this.optional = ~flags.indexOf('[');
42
  this.bool = !~flags.indexOf('-no-');
43
  flags = flags.split(/[ ,|]+/);
44
  if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
45
  this.long = flags.shift();
46
  this.description = description || '';
47
}
48
49
/**
50
 * Return option name.
51
 *
52
 * @return {String}
53
 * @api private
54
 */
55
56
Option.prototype.name = function() {
57
  return this.long
58
    .replace('--', '')
59
    .replace('no-', '');
60
};
61
62
/**
63
 * Check if `arg` matches the short or long flag.
64
 *
65
 * @param {String} arg
66
 * @return {Boolean}
67
 * @api private
68
 */
69
70
Option.prototype.is = function(arg) {
71
  return arg == this.short || arg == this.long;
72
};
73
74
/**
75
 * Initialize a new `Command`.
76
 *
77
 * @param {String} name
78
 * @api public
79
 */
80
81
function Command(name) {
82
  this.commands = [];
83
  this.options = [];
84
  this._execs = {};
85
  this._allowUnknownOption = false;
86
  this._args = [];
87
  this._name = name || '';
88
}
89
90
/**
91
 * Inherit from `EventEmitter.prototype`.
92
 */
93
94
Command.prototype.__proto__ = EventEmitter.prototype;
95
96
/**
97
 * Add command `name`.
98
 *
99
 * The `.action()` callback is invoked when the
100
 * command `name` is specified via __ARGV__,
101
 * and the remaining arguments are applied to the
102
 * function for access.
103
 *
104
 * When the `name` is "*" an un-matched command
105
 * will be passed as the first arg, followed by
106
 * the rest of __ARGV__ remaining.
107
 *
108
 * Examples:
109
 *
110
 *      program
111
 *        .version('0.0.1')
112
 *        .option('-C, --chdir <path>', 'change the working directory')
113
 *        .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
114
 *        .option('-T, --no-tests', 'ignore test hook')
115
 *
116
 *      program
117
 *        .command('setup')
118
 *        .description('run remote setup commands')
119
 *        .action(function() {
120
 *          console.log('setup');
121
 *        });
122
 *
123
 *      program
124
 *        .command('exec <cmd>')
125
 *        .description('run the given remote command')
126
 *        .action(function(cmd) {
127
 *          console.log('exec "%s"', cmd);
128
 *        });
129
 *
130
 *      program
131
 *        .command('teardown <dir> [otherDirs...]')
132
 *        .description('run teardown commands')
133
 *        .action(function(dir, otherDirs) {
134
 *          console.log('dir "%s"', dir);
135
 *          if (otherDirs) {
136
 *            otherDirs.forEach(function (oDir) {
137
 *              console.log('dir "%s"', oDir);
138
 *            });
139
 *          }
140
 *        });
141
 *
142
 *      program
143
 *        .command('*')
144
 *        .description('deploy the given env')
145
 *        .action(function(env) {
146
 *          console.log('deploying "%s"', env);
147
 *        });
148
 *
149
 *      program.parse(process.argv);
150
  *
151
 * @param {String} name
152
 * @param {String} [desc] for git-style sub-commands
153
 * @return {Command} the new command
154
 * @api public
155
 */
156
157
Command.prototype.command = function(name, desc, opts) {
158
  opts = opts || {};
159
  var args = name.split(/ +/);
160
  var cmd = new Command(args.shift());
161
162
  if (desc) {
163
    cmd.description(desc);
164
    this.executables = true;
165
    this._execs[cmd._name] = true;
166
    if (opts.isDefault) this.defaultExecutable = cmd._name;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
167
  }
168
169
  cmd._noHelp = !!opts.noHelp;
170
  this.commands.push(cmd);
171
  cmd.parseExpectedArgs(args);
172
  cmd.parent = this;
173
174
  if (desc) return this;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
175
  return cmd;
176
};
177
178
/**
179
 * Define argument syntax for the top-level command.
180
 *
181
 * @api public
182
 */
183
184
Command.prototype.arguments = function (desc) {
185
  return this.parseExpectedArgs(desc.split(/ +/));
186
};
187
188
/**
189
 * Add an implicit `help [cmd]` subcommand
190
 * which invokes `--help` for the given command.
191
 *
192
 * @api private
193
 */
194
195
Command.prototype.addImplicitHelpCommand = function() {
196
  this.command('help [cmd]', 'display help for [cmd]');
197
};
198
199
/**
200
 * Parse expected `args`.
201
 *
202
 * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
203
 *
204
 * @param {Array} args
205
 * @return {Command} for chaining
206
 * @api public
207
 */
208
209
Command.prototype.parseExpectedArgs = function(args) {
210
  if (!args.length) return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
211
  var self = this;
212
  args.forEach(function(arg) {
213
    var argDetails = {
214
      required: false,
215
      name: '',
216
      variadic: false
217
    };
218
219
    switch (arg[0]) {
220
      case '<':
221
        argDetails.required = true;
222
        argDetails.name = arg.slice(1, -1);
223
        break;
224
      case '[':
225
        argDetails.name = arg.slice(1, -1);
226
        break;
227
    }
228
229
    if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') {
230
      argDetails.variadic = true;
231
      argDetails.name = argDetails.name.slice(0, -3);
232
    }
233
    if (argDetails.name) {
234
      self._args.push(argDetails);
235
    }
236
  });
237
  return this;
238
};
239
240
/**
241
 * Register callback `fn` for the command.
242
 *
243
 * Examples:
244
 *
245
 *      program
246
 *        .command('help')
247
 *        .description('display verbose help')
248
 *        .action(function() {
249
 *           // output help here
250
 *        });
251
 *
252
 * @param {Function} fn
253
 * @return {Command} for chaining
254
 * @api public
255
 */
256
257
Command.prototype.action = function(fn) {
258
  var self = this;
259
  var listener = function(args, unknown) {
260
    // Parse any so-far unknown options
261
    args = args || [];
262
    unknown = unknown || [];
263
264
    var parsed = self.parseOptions(unknown);
265
266
    // Output help if necessary
267
    outputHelpIfNecessary(self, parsed.unknown);
268
269
    // If there are still any unknown options, then we simply
270
    // die, unless someone asked for help, in which case we give it
271
    // to them, and then we die.
272
    if (parsed.unknown.length > 0) {
273
      self.unknownOption(parsed.unknown[0]);
274
    }
275
276
    // Leftover arguments need to be pushed back. Fixes issue #56
277
    if (parsed.args.length) args = parsed.args.concat(args);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
278
279
    self._args.forEach(function(arg, i) {
280
      if (arg.required && null == args[i]) {
0 ignored issues
show
Best Practice introduced by
Comparing null to args.i using the == operator is not safe. Consider using === instead.
Loading history...
281
        self.missingArgument(arg.name);
282
      } else if (arg.variadic) {
283
        if (i !== self._args.length - 1) {
284
          self.variadicArgNotLast(arg.name);
285
        }
286
287
        args[i] = args.splice(i);
288
      }
289
    });
290
291
    // Always append ourselves to the end of the arguments,
292
    // to make sure we match the number of arguments the user
293
    // expects
294
    if (self._args.length) {
295
      args[self._args.length] = self;
296
    } else {
297
      args.push(self);
298
    }
299
300
    fn.apply(self, args);
301
  };
302
  var parent = this.parent || this;
303
  var name = parent === this ? '*' : this._name;
304
  parent.on('command:' + name, listener);
305
  if (this._alias) parent.on('command:' + this._alias, listener);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
306
  return this;
307
};
308
309
/**
310
 * Define option with `flags`, `description` and optional
311
 * coercion `fn`.
312
 *
313
 * The `flags` string should contain both the short and long flags,
314
 * separated by comma, a pipe or space. The following are all valid
315
 * all will output this way when `--help` is used.
316
 *
317
 *    "-p, --pepper"
318
 *    "-p|--pepper"
319
 *    "-p --pepper"
320
 *
321
 * Examples:
322
 *
323
 *     // simple boolean defaulting to false
324
 *     program.option('-p, --pepper', 'add pepper');
325
 *
326
 *     --pepper
327
 *     program.pepper
328
 *     // => Boolean
329
 *
330
 *     // simple boolean defaulting to true
331
 *     program.option('-C, --no-cheese', 'remove cheese');
332
 *
333
 *     program.cheese
334
 *     // => true
335
 *
336
 *     --no-cheese
337
 *     program.cheese
338
 *     // => false
339
 *
340
 *     // required argument
341
 *     program.option('-C, --chdir <path>', 'change the working directory');
342
 *
343
 *     --chdir /tmp
344
 *     program.chdir
345
 *     // => "/tmp"
346
 *
347
 *     // optional argument
348
 *     program.option('-c, --cheese [type]', 'add cheese [marble]');
349
 *
350
 * @param {String} flags
351
 * @param {String} description
352
 * @param {Function|*} [fn] or default
353
 * @param {*} [defaultValue]
354
 * @return {Command} for chaining
355
 * @api public
356
 */
357
358
Command.prototype.option = function(flags, description, fn, defaultValue) {
359
  var self = this
360
    , option = new Option(flags, description)
361
    , oname = option.name()
362
    , name = camelcase(oname);
363
364
  // default as 3rd arg
365
  if (typeof fn != 'function') {
366
    if (fn instanceof RegExp) {
367
      var regex = fn;
368
      fn = function(val, def) {
369
        var m = regex.exec(val);
370
        return m ? m[0] : def;
371
      }
372
    }
373
    else {
374
      defaultValue = fn;
375
      fn = null;
376
    }
377
  }
378
379
  // preassign default value only for --no-*, [optional], or <required>
380
  if (false == option.bool || option.optional || option.required) {
0 ignored issues
show
Best Practice introduced by
Comparing false to option.bool using the == operator is not safe. Consider using === instead.
Loading history...
381
    // when --no-* we make sure default is true
382
    if (false == option.bool) defaultValue = true;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
383
    // preassign only if we have a default
384
    if (undefined !== defaultValue) self[name] = defaultValue;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
385
  }
386
387
  // register the option
388
  this.options.push(option);
389
390
  // when it's passed assign the value
391
  // and conditionally invoke the callback
392
  this.on('option:' + oname, function(val) {
393
    // coercion
394
    if (null !== val && fn) val = fn(val, undefined === self[name]
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
395
      ? defaultValue
396
      : self[name]);
397
398
    // unassigned or bool
399
    if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) {
400
      // if no value, bool true, and we have a default, then use it!
401
      if (null == val) {
0 ignored issues
show
Best Practice introduced by
Comparing null to val using the == operator is not safe. Consider using === instead.
Loading history...
402
        self[name] = option.bool
403
          ? defaultValue || true
404
          : false;
405
      } else {
406
        self[name] = val;
407
      }
408
    } else if (null !== val) {
409
      // reassign
410
      self[name] = val;
411
    }
412
  });
413
414
  return this;
415
};
416
417
/**
418
 * Allow unknown options on the command line.
419
 *
420
 * @param {Boolean} arg if `true` or omitted, no error will be thrown
421
 * for unknown options.
422
 * @api public
423
 */
424
Command.prototype.allowUnknownOption = function(arg) {
425
    this._allowUnknownOption = arguments.length === 0 || arg;
426
    return this;
427
};
428
429
/**
430
 * Parse `argv`, settings options and invoking commands when defined.
431
 *
432
 * @param {Array} argv
433
 * @return {Command} for chaining
434
 * @api public
435
 */
436
437
Command.prototype.parse = function(argv) {
438
  // implicit help
439
  if (this.executables) this.addImplicitHelpCommand();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
440
441
  // store raw args
442
  this.rawArgs = argv;
443
444
  // guess name
445
  this._name = this._name || basename(argv[1], '.js');
446
447
  // github-style sub-commands with no sub-command
448
  if (this.executables && argv.length < 3 && !this.defaultExecutable) {
449
    // this user needs help
450
    argv.push('--help');
451
  }
452
453
  // process argv
454
  var parsed = this.parseOptions(this.normalize(argv.slice(2)));
455
  var args = this.args = parsed.args;
456
457
  var result = this.parseArgs(this.args, parsed.unknown);
458
459
  // executable sub-commands
460
  var name = result.args[0];
461
462
  var aliasCommand = null;
463
  // check alias of sub commands
464
  if (name) {
465
    aliasCommand = this.commands.filter(function(command) {
466
      return command.alias() === name;
467
    })[0];
468
  }
469
470
  if (this._execs[name] && typeof this._execs[name] != "function") {
471
    return this.executeSubCommand(argv, args, parsed.unknown);
472
  } else if (aliasCommand) {
473
    // is alias of a subCommand
474
    args[0] = aliasCommand._name;
475
    return this.executeSubCommand(argv, args, parsed.unknown);
476
  } else if (this.defaultExecutable) {
477
    // use the default subcommand
478
    args.unshift(this.defaultExecutable);
479
    return this.executeSubCommand(argv, args, parsed.unknown);
480
  }
481
482
  return result;
483
};
484
485
/**
486
 * Execute a sub-command executable.
487
 *
488
 * @param {Array} argv
489
 * @param {Array} args
490
 * @param {Array} unknown
491
 * @api private
492
 */
493
494
Command.prototype.executeSubCommand = function(argv, args, unknown) {
495
  args = args.concat(unknown);
496
497
  if (!args.length) this.help();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
498
  if ('help' == args[0] && 1 == args.length) this.help();
0 ignored issues
show
Best Practice introduced by
Comparing 1 to args.length using the == operator is not safe. Consider using === instead.
Loading history...
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
499
500
  // <cmd> --help
501
  if ('help' == args[0]) {
502
    args[0] = args[1];
503
    args[1] = '--help';
504
  }
505
506
  // executable
507
  var f = argv[1];
508
  // name of the subcommand, link `pm-install`
509
  var bin = basename(f, '.js') + '-' + args[0];
510
511
512
  // In case of globally installed, get the base dir where executable
513
  //  subcommand file should be located at
514
  var baseDir
515
    , link = fs.lstatSync(f).isSymbolicLink() ? fs.readlinkSync(f) : f;
516
517
  // when symbolink is relative path
518
  if (link !== f && link.charAt(0) !== '/') {
519
    link = path.join(dirname(f), link)
520
  }
521
  baseDir = dirname(link);
522
523
  // prefer local `./<bin>` to bin in the $PATH
524
  var localBin = path.join(baseDir, bin);
525
526
  // whether bin file is a js script with explicit `.js` extension
527
  var isExplicitJS = false;
528
  if (exists(localBin + '.js')) {
529
    bin = localBin + '.js';
530
    isExplicitJS = true;
531
  } else if (exists(localBin)) {
532
    bin = localBin;
533
  }
534
535
  args = args.slice(1);
536
537
  var proc;
538
  if (process.platform !== 'win32') {
539
    if (isExplicitJS) {
540
      args.unshift(bin);
541
      // add executable arguments to spawn
542
      args = (process.execArgv || []).concat(args);
543
544
      proc = spawn('node', args, { stdio: 'inherit', customFds: [0, 1, 2] });
545
    } else {
546
      proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] });
547
    }
548
  } else {
549
    args.unshift(bin);
550
    proc = spawn(process.execPath, args, { stdio: 'inherit'});
551
  }
552
553
  var signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
554
  signals.forEach(function(signal) {
555
    process.on(signal, function(){
556
      if ((proc.killed === false) && (proc.exitCode === null)){
557
        proc.kill(signal);
558
      }
559
    });
560
  });
561
  proc.on('close', process.exit.bind(process));
562
  proc.on('error', function(err) {
563
    if (err.code == "ENOENT") {
564
      console.error('\n  %s(1) does not exist, try --help\n', bin);
565
    } else if (err.code == "EACCES") {
566
      console.error('\n  %s(1) not executable. try chmod or run with root\n', bin);
567
    }
568
    process.exit(1);
0 ignored issues
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
569
  });
570
571
  // Store the reference to the child process
572
  this.runningCommand = proc;
573
};
574
575
/**
576
 * Normalize `args`, splitting joined short flags. For example
577
 * the arg "-abc" is equivalent to "-a -b -c".
578
 * This also normalizes equal sign and splits "--abc=def" into "--abc def".
579
 *
580
 * @param {Array} args
581
 * @return {Array}
582
 * @api private
583
 */
584
585
Command.prototype.normalize = function(args) {
586
  var ret = []
587
    , arg
588
    , lastOpt
589
    , index;
590
591
  for (var i = 0, len = args.length; i < len; ++i) {
592
    arg = args[i];
593
    if (i > 0) {
594
      lastOpt = this.optionFor(args[i-1]);
595
    }
596
597
    if (arg === '--') {
598
      // Honor option terminator
599
      ret = ret.concat(args.slice(i));
600
      break;
601
    } else if (lastOpt && lastOpt.required) {
602
      ret.push(arg);
603
    } else if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) {
604
      arg.slice(1).split('').forEach(function(c) {
605
        ret.push('-' + c);
606
      });
607
    } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {
608
      ret.push(arg.slice(0, index), arg.slice(index + 1));
609
    } else {
610
      ret.push(arg);
611
    }
612
  }
613
614
  return ret;
615
};
616
617
/**
618
 * Parse command `args`.
619
 *
620
 * When listener(s) are available those
621
 * callbacks are invoked, otherwise the "*"
622
 * event is emitted and those actions are invoked.
623
 *
624
 * @param {Array} args
625
 * @return {Command} for chaining
626
 * @api private
627
 */
628
629
Command.prototype.parseArgs = function(args, unknown) {
630
  var name;
631
632
  if (args.length) {
633
    name = args[0];
634
    if (this.listeners('command:' + name).length) {
635
      this.emit('command:' + args.shift(), args, unknown);
636
    } else {
637
      this.emit('command:*', args);
638
    }
639
  } else {
640
    outputHelpIfNecessary(this, unknown);
641
642
    // If there were no args and we have unknown options,
643
    // then they are extraneous and we need to error.
644
    if (unknown.length > 0) {
645
      this.unknownOption(unknown[0]);
646
    }
647
  }
648
649
  return this;
650
};
651
652
/**
653
 * Return an option matching `arg` if any.
654
 *
655
 * @param {String} arg
656
 * @return {Option}
657
 * @api private
658
 */
659
660
Command.prototype.optionFor = function(arg) {
661
  for (var i = 0, len = this.options.length; i < len; ++i) {
662
    if (this.options[i].is(arg)) {
663
      return this.options[i];
664
    }
665
  }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
666
};
667
668
/**
669
 * Parse options from `argv` returning `argv`
670
 * void of these options.
671
 *
672
 * @param {Array} argv
673
 * @return {Array}
674
 * @api public
675
 */
676
677
Command.prototype.parseOptions = function(argv) {
678
  var args = []
679
    , len = argv.length
680
    , literal
681
    , option
682
    , arg;
683
684
  var unknownOptions = [];
685
686
  // parse options
687
  for (var i = 0; i < len; ++i) {
688
    arg = argv[i];
689
690
    // literal args after --
691
    if (literal) {
692
      args.push(arg);
693
      continue;
694
    }
695
696
    if ('--' == arg) {
697
      literal = true;
698
      continue;
699
    }
700
701
    // find matching Option
702
    option = this.optionFor(arg);
703
704
    // option is defined
705
    if (option) {
706
      // requires arg
707
      if (option.required) {
708
        arg = argv[++i];
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
709
        if (null == arg) return this.optionMissingArgument(option);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
Best Practice introduced by
Comparing null to arg using the == operator is not safe. Consider using === instead.
Loading history...
710
        this.emit('option:' + option.name(), arg);
711
      // optional arg
712
      } else if (option.optional) {
713
        arg = argv[i+1];
714
        if (null == arg || ('-' == arg[0] && '-' != arg)) {
715
          arg = null;
716
        } else {
717
          ++i;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
718
        }
719
        this.emit('option:' + option.name(), arg);
720
      // bool
721
      } else {
722
        this.emit('option:' + option.name());
723
      }
724
      continue;
725
    }
726
727
    // looks like an option
728
    if (arg.length > 1 && '-' == arg[0]) {
729
      unknownOptions.push(arg);
730
731
      // If the next argument looks like it might be
732
      // an argument for this option, we pass it on.
733
      // If it isn't, then it'll simply be ignored
734
      if (argv[i+1] && '-' != argv[i+1][0]) {
735
        unknownOptions.push(argv[++i]);
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
736
      }
737
      continue;
738
    }
739
740
    // arg
741
    args.push(arg);
742
  }
743
744
  return { args: args, unknown: unknownOptions };
745
};
746
747
/**
748
 * Return an object containing options as key-value pairs
749
 *
750
 * @return {Object}
751
 * @api public
752
 */
753
Command.prototype.opts = function() {
754
  var result = {}
755
    , len = this.options.length;
756
757
  for (var i = 0 ; i < len; i++) {
758
    var key = camelcase(this.options[i].name());
759
    result[key] = key === 'version' ? this._version : this[key];
760
  }
761
  return result;
762
};
763
764
/**
765
 * Argument `name` is missing.
766
 *
767
 * @param {String} name
768
 * @api private
769
 */
770
771
Command.prototype.missingArgument = function(name) {
772
  console.error();
773
  console.error("  error: missing required argument `%s'", name);
774
  console.error();
775
  process.exit(1);
0 ignored issues
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
776
};
777
778
/**
779
 * `Option` is missing an argument, but received `flag` or nothing.
780
 *
781
 * @param {String} option
782
 * @param {String} flag
783
 * @api private
784
 */
785
786
Command.prototype.optionMissingArgument = function(option, flag) {
787
  console.error();
788
  if (flag) {
789
    console.error("  error: option `%s' argument missing, got `%s'", option.flags, flag);
790
  } else {
791
    console.error("  error: option `%s' argument missing", option.flags);
792
  }
793
  console.error();
794
  process.exit(1);
0 ignored issues
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
795
};
796
797
/**
798
 * Unknown option `flag`.
799
 *
800
 * @param {String} flag
801
 * @api private
802
 */
803
804
Command.prototype.unknownOption = function(flag) {
805
  if (this._allowUnknownOption) return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
806
  console.error();
807
  console.error("  error: unknown option `%s'", flag);
808
  console.error();
809
  process.exit(1);
0 ignored issues
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
810
};
811
812
/**
813
 * Variadic argument with `name` is not the last argument as required.
814
 *
815
 * @param {String} name
816
 * @api private
817
 */
818
819
Command.prototype.variadicArgNotLast = function(name) {
820
  console.error();
821
  console.error("  error: variadic arguments must be last `%s'", name);
822
  console.error();
823
  process.exit(1);
0 ignored issues
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
824
};
825
826
/**
827
 * Set the program version to `str`.
828
 *
829
 * This method auto-registers the "-V, --version" flag
830
 * which will print the version number when passed.
831
 *
832
 * @param {String} str
833
 * @param {String} [flags]
834
 * @return {Command} for chaining
835
 * @api public
836
 */
837
838
Command.prototype.version = function(str, flags) {
839
  if (0 == arguments.length) return this._version;
0 ignored issues
show
Best Practice introduced by
Comparing 0 to arguments.length using the == operator is not safe. Consider using === instead.
Loading history...
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
840
  this._version = str;
841
  flags = flags || '-V, --version';
842
  this.option(flags, 'output the version number');
843
  this.on('option:version', function() {
844
    process.stdout.write(str + '\n');
845
    process.exit(0);
0 ignored issues
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
846
  });
847
  return this;
848
};
849
850
/**
851
 * Set the description to `str`.
852
 *
853
 * @param {String} str
854
 * @return {String|Command}
855
 * @api public
856
 */
857
858
Command.prototype.description = function(str) {
859
  if (0 === arguments.length) return this._description;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
860
  this._description = str;
861
  return this;
862
};
863
864
/**
865
 * Set an alias for the command
866
 *
867
 * @param {String} alias
868
 * @return {String|Command}
869
 * @api public
870
 */
871
872
Command.prototype.alias = function(alias) {
873
  var command = this;
874
  if(this.commands.length !== 0) {
875
    command = this.commands[this.commands.length - 1]
876
  }
877
878
  if (arguments.length === 0) return command._alias;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
879
880
  command._alias = alias;
881
  return this;
882
};
883
884
/**
885
 * Set / get the command usage `str`.
886
 *
887
 * @param {String} str
888
 * @return {String|Command}
889
 * @api public
890
 */
891
892
Command.prototype.usage = function(str) {
893
  var args = this._args.map(function(arg) {
894
    return humanReadableArgName(arg);
895
  });
896
897
  var usage = '[options]'
898
    + (this.commands.length ? ' [command]' : '')
899
    + (this._args.length ? ' ' + args.join(' ') : '');
900
901
  if (0 == arguments.length) return this._usage || usage;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
Best Practice introduced by
Comparing 0 to arguments.length using the == operator is not safe. Consider using === instead.
Loading history...
902
  this._usage = str;
903
904
  return this;
905
};
906
907
/**
908
 * Get or set the name of the command
909
 *
910
 * @param {String} str
911
 * @return {String|Command}
912
 * @api public
913
 */
914
915
Command.prototype.name = function(str) {
916
  if (0 === arguments.length) return this._name;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
917
  this._name = str;
918
  return this;
919
};
920
921
/**
922
 * Return the largest option length.
923
 *
924
 * @return {Number}
925
 * @api private
926
 */
927
928
Command.prototype.largestOptionLength = function() {
929
  return this.options.reduce(function(max, option) {
930
    return Math.max(max, option.flags.length);
931
  }, 0);
932
};
933
934
/**
935
 * Return help for options.
936
 *
937
 * @return {String}
938
 * @api private
939
 */
940
941
Command.prototype.optionHelp = function() {
942
  var width = this.largestOptionLength();
943
944
  // Append the help information
945
  return this.options.map(function(option) {
946
      return pad(option.flags, width) + '  ' + option.description;
947
    }).concat([pad('-h, --help', width) + '  ' + 'output usage information'])
948
    .join('\n');
949
};
950
951
/**
952
 * Return command help documentation.
953
 *
954
 * @return {String}
955
 * @api private
956
 */
957
958
Command.prototype.commandHelp = function() {
959
  if (!this.commands.length) return '';
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
960
961
  var commands = this.commands.filter(function(cmd) {
962
    return !cmd._noHelp;
963
  }).map(function(cmd) {
964
    var args = cmd._args.map(function(arg) {
965
      return humanReadableArgName(arg);
966
    }).join(' ');
967
968
    return [
969
      cmd._name
970
        + (cmd._alias ? '|' + cmd._alias : '')
971
        + (cmd.options.length ? ' [options]' : '')
972
        + ' ' + args
973
      , cmd._description
974
    ];
975
  });
976
977
  var width = commands.reduce(function(max, command) {
978
    return Math.max(max, command[0].length);
979
  }, 0);
980
981
  return [
982
    ''
983
    , '  Commands:'
984
    , ''
985
    , commands.map(function(cmd) {
986
      var desc = cmd[1] ? '  ' + cmd[1] : '';
987
      return pad(cmd[0], width) + desc;
988
    }).join('\n').replace(/^/gm, '    ')
989
    , ''
990
  ].join('\n');
991
};
992
993
/**
994
 * Return program help documentation.
995
 *
996
 * @return {String}
997
 * @api private
998
 */
999
1000
Command.prototype.helpInformation = function() {
1001
  var desc = [];
1002
  if (this._description) {
1003
    desc = [
1004
      '  ' + this._description
1005
      , ''
1006
    ];
1007
  }
1008
1009
  var cmdName = this._name;
1010
  if (this._alias) {
1011
    cmdName = cmdName + '|' + this._alias;
1012
  }
1013
  var usage = [
1014
    ''
1015
    ,'  Usage: ' + cmdName + ' ' + this.usage()
1016
    , ''
1017
  ];
1018
1019
  var cmds = [];
1020
  var commandHelp = this.commandHelp();
1021
  if (commandHelp) cmds = [commandHelp];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
1022
1023
  var options = [
1024
    ''
1025
    , '  Options:'
1026
    , ''
1027
    , '' + this.optionHelp().replace(/^/gm, '    ')
1028
    , ''
1029
  ];
1030
1031
  return usage
1032
    .concat(desc)
1033
    .concat(options)
1034
    .concat(cmds)
1035
    .join('\n');
1036
};
1037
1038
/**
1039
 * Output help information for this command
1040
 *
1041
 * @api public
1042
 */
1043
1044
Command.prototype.outputHelp = function(cb) {
1045
  if (!cb) {
1046
    cb = function(passthru) {
1047
      return passthru;
1048
    }
1049
  }
1050
  process.stdout.write(cb(this.helpInformation()));
1051
  this.emit('--help');
1052
};
1053
1054
/**
1055
 * Output help information and exit.
1056
 *
1057
 * @api public
1058
 */
1059
1060
Command.prototype.help = function(cb) {
1061
  this.outputHelp(cb);
1062
  process.exit();
0 ignored issues
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
1063
};
1064
1065
/**
1066
 * Camel-case the given `flag`
1067
 *
1068
 * @param {String} flag
1069
 * @return {String}
1070
 * @api private
1071
 */
1072
1073
function camelcase(flag) {
1074
  return flag.split('-').reduce(function(str, word) {
1075
    return str + word[0].toUpperCase() + word.slice(1);
1076
  });
1077
}
1078
1079
/**
1080
 * Pad `str` to `width`.
1081
 *
1082
 * @param {String} str
1083
 * @param {Number} width
1084
 * @return {String}
1085
 * @api private
1086
 */
1087
1088
function pad(str, width) {
1089
  var len = Math.max(0, width - str.length);
1090
  return str + Array(len + 1).join(' ');
1091
}
1092
1093
/**
1094
 * Output help information if necessary
1095
 *
1096
 * @param {Command} command to output help for
1097
 * @param {Array} array of options to search for -h or --help
1098
 * @api private
1099
 */
1100
1101
function outputHelpIfNecessary(cmd, options) {
1102
  options = options || [];
1103
  for (var i = 0; i < options.length; i++) {
1104
    if (options[i] == '--help' || options[i] == '-h') {
1105
      cmd.outputHelp();
1106
      process.exit(0);
0 ignored issues
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
1107
    }
1108
  }
1109
}
1110
1111
/**
1112
 * Takes an argument an returns its human readable equivalent for help usage.
1113
 *
1114
 * @param {Object} arg
1115
 * @return {String}
1116
 * @api private
1117
 */
1118
1119
function humanReadableArgName(arg) {
1120
  var nameOutput = arg.name + (arg.variadic === true ? '...' : '');
1121
1122
  return arg.required
1123
    ? '<' + nameOutput + '>'
1124
    : '[' + nameOutput + ']'
1125
}
1126
1127
// for versions before node v0.8 when there weren't `fs.existsSync`
1128
function exists(file) {
1129
  try {
1130
    if (fs.statSync(file).isFile()) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if fs.statSync(file).isFile() is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
1131
      return true;
1132
    }
1133
  } catch (e) {
1134
    return false;
1135
  }
1136
}
1137
1138